#include "Config.h"
#include "DBWorker.h"
#include "../Server.h"
#include "DB/DBConnectionMgr.h"
#include "DB/DBExecutor.h"

DBWorker::DBWorker(UInt8 worker_)
	: WorkerRunner<DBMsgHandler>(500), _tid(worker_)
{

}

DBWorker::~DBWorker()
{

}

bool DBWorker::init()
{
	m_ObjectExecutor.reset(gObjectDBConnectionMgr->GetExecutor());
	m_PlatExecutor.reset(gPlatDBConnectionMgr->GetExecutor());
	return true;
}

bool DBWorker::postInit()
{
	return true;
}

void DBWorker::unInit()
{
	onTimer();
	m_ObjectExecutor.reset();
	m_PlatExecutor.reset();
}

void DBWorker::onTimer()
{
	{
		while (m_ObjectExecutor.get() == NULL || !m_ObjectExecutor->isConnected())
		{
			Thread::sleep(500);
			m_ObjectExecutor.reset(gObjectDBConnectionMgr->GetExecutor());
			TRACE_LOG("start reconnect to Database ...");
		}
		std::vector<const char *> l;
		{
			FastMutex::ScopedLock lk(m_ObjectMutex);
			if (m_ObjectUpdateItems.empty())
				return;
			l = m_ObjectUpdateItems;
			m_ObjectUpdateItems.clear();
		}
		std::vector<const char *>::iterator it;
		for (it = l.begin(); it != l.end(); ++it)
		{
			bool r = DoOjbectQuery(*it);
			TRACE_LOG("[%s] -> %d", *it, r ? 1 : 0);
			delete[] * it;
		}
	}
	//
	{
	while (m_PlatExecutor.get() == NULL || !m_PlatExecutor->isConnected())
	{
		Thread::sleep(500);
		m_PlatExecutor.reset(gPlatDBConnectionMgr->GetExecutor());
		TRACE_LOG("start reconnect to Database ...");
	}
	std::vector<const char *> l;
	{
		FastMutex::ScopedLock lk(m_PlatMutex);
		if (m_PlatUpdateItems.empty())
			return;
		l = m_PlatUpdateItems;
		m_PlatUpdateItems.clear();
	}
	std::vector<const char *>::iterator it;
	for (it = l.begin(); it != l.end(); ++it)
	{
		bool r = DoPlatQuery(*it);
		TRACE_LOG("[%s] -> %d", *it, r ? 1 : 0);
		delete[] * it;
	}
}
}

void DBWorker::onPause()
{
	{
		m_ObjectExecutor->setMgr(NULL);
		m_ObjectExecutor.reset();
		DBConfig dbc = cfg.getObjectConfig();
		gObjectDBConnectionMgr->Init(dbc._host.c_str(), dbc._user.c_str(), dbc._passwd.c_str(), dbc._name.c_str(), 4, 32, dbc._port);
	}
	//
	{
	m_PlatExecutor->setMgr(NULL);
	m_PlatExecutor.reset();
	DBConfig dbc = cfg.getPlatConfig();
	gPlatDBConnectionMgr->Init(dbc._host.c_str(), dbc._user.c_str(), dbc._passwd.c_str(), dbc._name.c_str(), 4, 32, dbc._port);
}
	//
	Resume();
}


void DBWorker::PushObjectUpdateData(const char * fmt, ...)
{
	/* Guess we need no more than 256 bytes. */
	int size = 256;

	char *p = new(std::nothrow) char[size];
	if (p == NULL)
		return;

	while (1) {
		va_list ap;
		/* Try to print in the allocated space. */
		va_start(ap, fmt);
		int n = vsnprintf(p, size, fmt, ap);
		va_end(ap);
		/* If that worked, return the string. */
		if (n > -1 && n < size)
			break;
		/* Else try again with more space. */
		if (n > -1)    /* glibc 2.1 */
			size = n + 1; /* precisely what is needed */
		else           /* glibc 2.0 */
			size *= 2;  /* twice the old size */
		delete[] p;
		if ((p = new(std::nothrow) char[size]) == NULL) {
			return;
		}
	}

	FastMutex::ScopedLock lk(m_ObjectMutex);
	m_ObjectUpdateItems.push_back(p);
	DB().GetLog()->OutInfo("Push [%s]\n", p);
}

void DBWorker::PushPlatUpdateData(const char * fmt, ...)
{
	/* Guess we need no more than 256 bytes. */
	int size = 256;

	char *p = new(std::nothrow) char[size];
	if (p == NULL)
		return;

	while (1) {
		va_list ap;
		/* Try to print in the allocated space. */
		va_start(ap, fmt);
		int n = vsnprintf(p, size, fmt, ap);
		va_end(ap);
		/* If that worked, return the string. */
		if (n > -1 && n < size)
			break;
		/* Else try again with more space. */
		if (n > -1)    /* glibc 2.1 */
			size = n + 1; /* precisely what is needed */
		else           /* glibc 2.0 */
			size *= 2;  /* twice the old size */
		delete[] p;
		if ((p = new(std::nothrow) char[size]) == NULL) {
			return;
		}
	}

	FastMutex::ScopedLock lk(m_PlatMutex);
	m_PlatUpdateItems.push_back(p);
	DB().GetLog()->OutInfo("Push [%s]\n", p);
}

bool DBWorker::DoOjbectQuery(const char* query)
{
	if (query == NULL)
		return false;
	DBResult r;
	while ((r = m_ObjectExecutor->Execute(query)) == DB_ConnLost)
	{
		TRACE_LOG("Lost connection to Database, retrying...");
		Thread::sleep(500);
	}
	return r == DB_OK;
}

bool DBWorker::DoPlatQuery(const char* query)
{
	if (query == NULL)
		return false;
	DBResult r;
	while ((r = m_PlatExecutor->Execute(query)) == DB_ConnLost)
	{
		TRACE_LOG("Lost connection to Database, retrying...");
		Thread::sleep(500);
	}
	return r == DB_OK;
}

std::string DBWorker::getLogName()
{
	std::string logPath = "log/";
	logPath.append(SERVER_NAME);
	logPath.append("/");
	std::string logDir = SERVER().getFilePath(logPath);
	return logDir;
}